#include "deformablemesh.h"

#include <windows.h>
#include <sstream>
#include <fstream>

#include "consoleoutput.h"
#include "epslon.h"
#include "linearvertexcluster.h"
#include "quadraticvertexcluster.h"

const float DeformableMesh::GRAVITY_ACC = 1.8f;
const float DeformableMesh::RESTITUTION = 0.15f;
const float DeformableMesh::ENERGY_PRESERVATION = 0.99f;
const float DeformableMesh::ACCEPTABLE_DEEPNESS = 0.0001f;
const float DeformableMesh::FLOOR_HEIGHT = -2.5f;
const float DeformableMesh::INTERPENETRATION_CORRECTION_FACTOR = 3000.0f;

float vertexDistance( ModelOBJ::Vertex& a, ModelOBJ::Vertex& b )
{
	return sqrt( 
		pow( a.position[ 0 ] - b.position[ 0 ], 2 ) +
		pow( a.position[ 1 ] - b.position[ 1 ], 2 ) +
		pow( a.position[ 2 ] - b.position[ 2 ], 2 )
	);
}

DeformableMesh::DeformableMesh( DeformationMode mode, float rigidity )
{
	reset( mode, rigidity );
}

DeformableMesh::DeformableMesh()
{
	reset( DEFORMATION_MODE_LINEAR, 0.0f );
}

bool DeformableMesh::import( const char* fileName )
{
	reset( deformationMode, rigidity );

	std::ifstream descFileHandler( fileName );
	if( descFileHandler.is_open() )
	{
		std::string modelFileName;
		std::string nOfClustersString;

		if( descFileHandler.good() )
			getline( descFileHandler, modelFileName );

		if( descFileHandler.good() )
		{
			getline( descFileHandler, nOfClustersString );
			numberOfClusters = (int) atoi( nOfClustersString.data() );
		}

		// creating clusters
		for( int i = 0; i < numberOfClusters; i++ )
		{
			switch( deformationMode )
			{
			case DEFORMATION_MODE_LINEAR:
				clusters.push_back( new LinearVertexCluster( *this, i + 1 ) );
				break;

			case DEFORMATION_MODE_QUADRATIC:
				clusters.push_back( new QuadraticVertexCluster( *this, i + 1 ) );
				break;
			}
		}

		// importing model and normalizing it
		ModelOBJ::import( modelFileName.data() );
		normalize( 1.0f, true );

		// loading vertices and arcs information
		numberOfVertices = getNumberOfVertices();
		//createArcs();

		// creating speed array and assigning default blocked status to free
		for( int i = 0; i < numberOfVertices; i++ )
		{
			vSpeed.push_back( ModelOBJ::Vertex() );
			vSpeed[ i ].position[ 0 ] = 
				vSpeed[ i ].position[ 1 ] = 
				vSpeed[ i ].position[ 2 ] = 0.0f;

			intermediatePosition.push_back( ModelOBJ::Vertex() );
			intermediatePosition[ i ].position[ 0 ] = 
				intermediatePosition[ i ].position[ 1 ] = 
				intermediatePosition[ i ].position[ 2 ] = 0.0f;

			intermediateSpeed.push_back( ModelOBJ::Vertex() );
			intermediateSpeed[ i ].position[ 0 ] = 
				intermediateSpeed[ i ].position[ 1 ] = 
				intermediateSpeed[ i ].position[ 2 ] = 0.0f;

			fractureSpeed.push_back( ModelOBJ::Vertex() );
			fractureSpeed[ i ].position[ 0 ] = 
				fractureSpeed[ i ].position[ 1 ] = 
				fractureSpeed[ i ].position[ 2 ] = 0.0f;

			vertexBlockedStatus.push_back( VERTEX_BLOCK_MODE_FREE );
		}
	}

	loadingVertexWeightInformation( descFileHandler );

	// loading cluster and pre-calculation
	for( int i = 0; i < numberOfClusters; i++ )
		clusters[ i ]->initialize();

	// connecting clusters
	for( int i = 0; i < numberOfClusters; i++ )
	{
		for( int j = 0; j < numberOfClusters; j++ )
		{
			switch( i )
			{
			case 0: if( j != 1 && j != 2 && j != 3 ) continue; break;
			case 1: if( j != 0 && j != 4 && j != 7 ) continue; break;
			case 2: if( j != 0 && j != 4 && j != 5 ) continue; break;
			case 3: if( j != 0 && j != 5 && j != 7 ) continue; break;
			case 4: if( j != 1 && j != 2 && j != 6 ) continue; break;
			case 5: if( j != 2 && j != 3 && j != 6 ) continue; break;
			case 6: if( j != 2 && j != 4 && j != 5 ) continue; break;
			case 7: if( j != 1 && j != 3 && j != 6 ) continue; break;
			}

			if( i == j )
				continue;

			float cX1, cY1, cZ1, cX2, cY2, cZ2;
			clusters[i]->getCenterOfMass( &cX1, &cY1, &cZ1 );
			clusters[j]->getCenterOfMass( &cX2, &cY2, &cZ2 );
			float distance = sqrt( pow( cX1 - cX2, 2 ) + pow( cY1 - cY2, 2 ) + pow( cZ1 - cZ2, 2 ) );
			clusters[i]->addConnection( j, distance );
			clusters[j]->addConnection( i, distance );
		}
	}

	return true;
}

void DeformableMesh::update( float dt )
{
	if( simulationState == SIMULATION_STATE_STOPPED )
		return;

	static int relaxationCount = 0;
	if( isSimulationStepByStep )
	{
		switch( simulationState )
		{
		case SIMULATION_STATE_APPLYING_FORCES:
			applyForces( dt );
			CONSOLE( "Forces: " << deepness );
			simulationState = SIMULATION_STATE_COLLISION_CONSTRAINTS;
			break;

		case SIMULATION_STATE_COLLISION_CONSTRAINTS:
			applyCollisionConstraints( dt );
			preparePositionAndSpeed();
			CONSOLE( "Collision: " << deepness );
			simulationState = SIMULATION_STATE_DEFORMABLE_BODY_CONSTRAINTS;
			break;

		case SIMULATION_STATE_DEFORMABLE_BODY_CONSTRAINTS:
			applyDeformableConstraints( dt );
			passToIntermediateValues();
			CONSOLE( "Constraints: " << deepness );

			relaxationCount++;
			simulationState = relaxationCount < RELAXATION_MAX_ITERATIONS? SIMULATION_STATE_COLLISION_CONSTRAINTS : SIMULATION_STATE_INTEGRATION_FINISH;
			break;

		case SIMULATION_STATE_INTEGRATION_FINISH:
			finishIntegration( dt );
			simulationState = SIMULATION_STATE_APPLYING_FORCES;
			relaxationCount = 0;
			break;
		}
		//
		//Color c;

		//switch( simulationState )
		//{
		//case 1:
		//	c.color[0] = 0.0f;	c.color[1] = 1.0f;	c.color[2] = 1.0f;
		//	break;
		//case 2:
		//	c.color[0] = 0.0f;	c.color[1] = 0.0f;	c.color[2] = 1.0f;
		//	break;
		//case 3:
		//	c.color[0] = 1.0f;	c.color[1] = 0.0f;	c.color[2] = 0.0f;
		//	break;
		//case 4:
		//	c.color[0] = 1.0f;	c.color[1] = 0.0f;	c.color[2] = 1.0f;
		//	break;
		//}

		//for( int i = 0; i < numberOfVertices; i++ )
		//{
		//	colorBuffer[ i ] = c;
		//}
	}
	else
		updateContinuous(dt);
}

void DeformableMesh::setVertexBlockMode( int vertexIndex, int blockMode )
{
	//vertexBlockedStatus[ vertexIndex ] = blockMode;
}

void DeformableMesh::rotateVertex( int vertexIndex, float angle )
{
	for( int i = 0; i < numberOfVertices; i++ )
	{
		if( i >= 81 && i < 162 )
		{
			float newX, newZ;
			float x = m_vertexBuffer[ i ].position[ 0 ];
			float z = m_vertexBuffer[ i ].position[ 2 ];

			newX = cos( angle ) * x - sin( angle ) * z;
			newZ = sin( angle ) * x + cos( angle ) * z;

			vSpeed[ i ].position[ 0 ] = ( newX - x ) / 10.0f;
			vSpeed[ i ].position[ 2 ] = ( newZ - z ) / 10.0f;
		}
	}
}

float DeformableMesh::getBeta()
{
	return beta;
}

float DeformableMesh::getAlpha()
{
	return alpha;
}

float DeformableMesh::calculateRigidityFactor()
{
	return pow( alpha, 4.0f );
}

void DeformableMesh::calculateAlphaAndBeta()
{
	alpha = rigidity * 0.5f + 0.5f;
	beta = rigidity * -0.4f + 0.4f;
}

void DeformableMesh::setRigidity( float rigidity )
{
	rigidity = max( rigidity, 0.0f );
	rigidity = min( rigidity, 1.0f );
	this->rigidity = rigidity;
	calculateAlphaAndBeta();
}

void DeformableMesh::applyForces( float dt )
{
	deepness = 0.0f;

	for( int i = 0; i < numberOfVertices; i++ )
	{
		intermediateSpeed[ i ].position[ 0 ] = vSpeed[ i ].position[ 0 ] * ENERGY_PRESERVATION;
		intermediateSpeed[ i ].position[ 1 ] = vSpeed[ i ].position[ 1 ] * ENERGY_PRESERVATION;
		intermediateSpeed[ i ].position[ 2 ] = vSpeed[ i ].position[ 2 ] * ENERGY_PRESERVATION;

		//if( intermediatePosition[ i ].position[ 1 ] > FLOOR_HEIGHT + 0.1f ) 
		//{
			intermediateSpeed[ i ].position[ 1 ] -= GRAVITY_ACC * dt;
		//}

		if( i > 386 )
		{
			int a = 123;
		}

		intermediatePosition[ i ].position[ 0 ] = m_vertexBuffer[ i ].position[ 0 ] + dt * intermediateSpeed[ i ].position[ 0 ];
		intermediatePosition[ i ].position[ 1 ] = m_vertexBuffer[ i ].position[ 1 ] + dt * intermediateSpeed[ i ].position[ 1 ];
		intermediatePosition[ i ].position[ 2 ] = m_vertexBuffer[ i ].position[ 2 ] + dt * intermediateSpeed[ i ].position[ 2 ];

		updateDeepness( intermediatePosition[ i ].position[ 1 ] );
	}
}

void DeformableMesh::finishIntegration( float dt )
{
	for( int i = 0; i < numberOfVertices; i++ )
	{
		vSpeed[ i ].position[ 0 ] = intermediateSpeed[ i ].position[ 0 ];
		vSpeed[ i ].position[ 1 ] = intermediateSpeed[ i ].position[ 1 ];
		vSpeed[ i ].position[ 2 ] = intermediateSpeed[ i ].position[ 2 ];

		m_vertexBuffer[ i ].position[ 0 ] = intermediatePosition[ i ].position[ 0 ];
		m_vertexBuffer[ i ].position[ 1 ] = intermediatePosition[ i ].position[ 1 ];
		m_vertexBuffer[ i ].position[ 2 ] = intermediatePosition[ i ].position[ 2 ];
	}

	generateNormals();

	if( recalculateWeights && shouldRecalculate )
		for( int i = 0; i < numberOfClusters; i++ )
			clusters[ i ]->onWeightChanged();
}

void DeformableMesh::updateContinuous( float dt )
{
	applyForces( dt );

	applyCollisionConstraints( dt );
	preparePositionAndSpeed();

	for( int i = 0; i < 1; i++ )
	{
		applyDeformableConstraints( dt );
		passToIntermediateValues();
		applyCollisionConstraints( dt );
		preparePositionAndSpeed();
	}

	finishIntegration( dt );
}

void DeformableMesh::moveMesh( float dx, float dy )
{
	for( int i = 0; i < numberOfVertices; i++ )
		moveVertex( i, dx, dy, 0.0f );
}

void DeformableMesh::applyCollisionConstraints( float dt )
{
 	deepness = 0.0f;
	shouldRecalculate = false;

	for (int i = 0; i < numberOfVertices; i++)
	{
		//Color c;
		//c.color[ 0 ] = c.color[ 2 ] = 1.0f;
		//c.color[ 1 ] = 0.0f;

		if( intermediatePosition[ i ].position[ 1 ] < FLOOR_HEIGHT + 0.001 && intermediateSpeed[ i ].position[ 1 ] < 0.0f )
		{
			//c.color[ 0 ] = 0.0f;
			//c.color[ 1 ] = c.color[ 2 ] = 1.0f;

			if( recalculateWeights )
			{
				float newWeight = calculateNewVertexWeight( i );

				for( int j = 0, size = vertexClusters[ i ].size(); j < size; j++ )
				{
					std::pair<int,int> clusterIndexInfo = vertexClusters[ i ][ j ];
					VertexCluster* c = clusters[ clusterIndexInfo.first  ];
					c->setVertexWeight( clusterIndexInfo.second, c->getVertexWeight( clusterIndexInfo.second ) * newWeight );
				}

				intermediateSpeed[ i ].position[ 0 ] *= 0.7f;
				intermediateSpeed[ i ].position[ 1 ] *= -0.6f; //( 1.0f - RESTITUTION );
				intermediateSpeed[ i ].position[ 2 ] *= 0.7f;

				//CONSOLE( "Speed factor: " << ( 1.0f / newWeight ) );

				intermediatePosition[ i ].position[ 1 ] = FLOOR_HEIGHT;
				shouldRecalculate = true;
			}
			else 
			{
				intermediateSpeed[ i ].position[ 0 ] *= RESTITUTION;
				intermediateSpeed[ i ].position[ 1 ] *= -0.6f; //( 1.0f - RESTITUTION );
				intermediateSpeed[ i ].position[ 2 ] *= RESTITUTION;

				intermediatePosition[ i ].position[ 1 ] = FLOOR_HEIGHT;
				//shouldRecalculate = true;
			}
		}


		//colorBuffer[ i ] = c;
		updateDeepness( intermediatePosition[ i ].position[ 1 ] );
	}

	//for( int i = 0; i < numberOfClusters; i++ )
	//	clusters[ i ]->recalculateCenterOfMass();

	//static bool shouldCheckForFractures = true;
	//bool HACK;
	//if( shouldCheckForFractures )
	//{
	//	HACK = checkForFractures();
	//	shouldCheckForFractures = false;
	//}
	//else
	//	HACK = false;

	//CONSOLE( "Should Recalculate: " << shouldRecalculate );
	if( recalculateWeights && shouldRecalculate || checkForFractures() )
	{
		for( int i = 0; i < numberOfClusters; i++ )
			clusters[ i ]->onWeightChanged();
	}
}

void DeformableMesh::applyDeformableConstraints( float dt )
{
	deepness = 0.0f;

	for( int i = 0; i < numberOfClusters; i++ )
	{	
		float clusterDeepness = clusters[i]->update( dt );
		//if( i == 0 )
		//{
		//	float x, y, z;
		//	clusters[0]->getCenterOfMass( &x, &y, &z );
		//	//CONSOLE( "Center Of Mass: " << x << ", " << y << ", " << z << ")" );
		//}
		deepness = max( deepness, clusterDeepness );
	}
}

//float DeformableMesh::getDeepness()
//{
//	float deepness = 0.0f;
//
//	for( int i = 0; i < numberOfVertices; i++ )
//		deepness = max( -(m_vertexBuffer[ i ].position[ 1 ] - FLOOR_HEIGHT ), deepness );
//
//	CONSOLE( "deepness = " << deepness );
//	return deepness;
//}
//
//float DeformableMesh::getIntermediateDeepness()
//{
//	//float deepness = 0.0f;
//
//	//for( int i = 0; i < numberOfVertices; i++ )
//	//	deepness = max( -(intermediatePosition[ i ].position[ 1 ] + FLOOR_HEIGHT ), deepness );
//
//	////CONSOLE( "deepness = " << deepness );
//	//return deepness;
//	return 0.0f;
//}

Color* DeformableMesh::getColorBuffer()
{
	return &colorBuffer[0];
}

void DeformableMesh::loadingVertexWeightInformation( std::ifstream& fileHandle )
{
	std::string line;
	int vIndex = 0;

	while( fileHandle.good() )
	{
		getline( fileHandle, line);

		int start = 0;
		int end = 0;

		Color c;
		std::vector<std::pair<int,int>> vClusters = std::vector<std::pair<int,int>>();

		for( int i = 0; i < numberOfClusters + 3; i++ )
		{
			end = line.find(' ', start + 1 );

			if( i < numberOfClusters )
			{
				float weight = (float) atof( line.substr(start, end).data() );

				//if( weight < EPSLON * 10.0f )
				//{
					clusters[ i ]->addVertex( 
						&getVertex( vIndex ), 
						&vSpeed[ vIndex ],  
						&intermediatePosition[ vIndex ],  
						&intermediateSpeed[ vIndex ],
						weight
						);
					vClusters.push_back( std::pair<int,int>( i, clusters[ i ]->getNumberOfVertices() - 1 ) );
				//}
			}
			else
			{
				c.color[  i - numberOfClusters ] = floor( (float) atof( line.substr(start, end).data() ) ) / 255.0f;
			}

			start = line.find(' ', end );

		}

		//if( vIndex >= 81 && vIndex <= 161 )
		//{
		//	Color c2;
		//	if( vIndex >= 126 )
		//	{
		//		c2.color[ 0 ] = 0.0f;
		//		c2.color[ 1 ] = 1.0f;
		//		c2.color[ 2 ] = 0.0f;
		//	}
		//	else
		//	{
		//		c2.color[ 0 ] = 0.0f;
		//		c2.color[ 1 ] = 0.0f;
		//		c2.color[ 2 ] = 1.0f;
		//	}
		//	colorBuffer.push_back( c2 );
		//}
		//else
		//{
			colorBuffer.push_back( c );
		//}
			


		vertexClusters.push_back( vClusters );
		vIndex++;
	}
}

ModelOBJ::Vertex* DeformableMesh::getVertexBufferForDrawing()
{
	if( simulationState == SIMULATION_STATE_DEFORMABLE_BODY_CONSTRAINTS )
		return &intermediatePosition[0];
	else
		return &getVertex(0);
}

float DeformableMesh::calculateNewVertexWeight( int vertexIndex )
{
	return 1.0f - ( ( intermediatePosition[ vertexIndex ].position[ 1 ] - FLOOR_HEIGHT ) * INTERPENETRATION_CORRECTION_FACTOR );
}

void DeformableMesh::updateDeepness( float yPosition )
{
	deepness = max( deepness, -( yPosition - FLOOR_HEIGHT ) );
}

void DeformableMesh::preparePositionAndSpeed()
{
	for( int i = 0; i < numberOfVertices; i++ )
	{
		m_vertexBuffer[ i ].position[ 0 ] = m_vertexBuffer[ i ].position[ 1 ] = m_vertexBuffer[ i ].position[ 2 ] = 0.0f;
		vSpeed[ i ].position[ 0 ] = intermediateSpeed[ i ].position[ 0 ];
		vSpeed[ i ].position[ 1 ] = intermediateSpeed[ i ].position[ 1 ];
		vSpeed[ i ].position[ 2 ] = intermediateSpeed[ i ].position[ 2 ];
	}
}

void DeformableMesh::reset( DeformationMode mode, float rigidity )
{
	deformationMode = mode;
	simulationState = SIMULATION_STATE_APPLYING_FORCES;
	numberOfVertices = 0;
	numberOfClusters = 0;
	isSimulationStepByStep = true;
	plasticityMode = PLASTICITY_MODE_NONE;
	this->rigidity = rigidity;
	deepness = 0.0f;
	shouldRecalculate = false;
	colorBuffer = std::vector<Color>();
	vertexClusters = std::vector<std::vector<std::pair<int,int>>>();
	//arcs = std::vector<Arcs>();
	calculateAlphaAndBeta();
	setRecalculateWeights( false );

	vSpeed.clear();
	intermediatePosition.clear();
	intermediateSpeed.clear();
	vertexBlockedStatus.clear();
	clusters.clear();
}

void DeformableMesh::passToIntermediateValues()
{
	for( int i = 0; i < numberOfVertices; i++ )
	{
		intermediatePosition[ i ].position[ 0 ] = m_vertexBuffer[ i ].position[ 0 ];
		intermediatePosition[ i ].position[ 1 ] = m_vertexBuffer[ i ].position[ 1 ];
		intermediatePosition[ i ].position[ 2 ] = m_vertexBuffer[ i ].position[ 2 ];
		intermediateSpeed[ i ].position[ 0 ] = vSpeed[ i ].position[ 0 ];
		intermediateSpeed[ i ].position[ 1 ] = vSpeed[ i ].position[ 1 ];
		intermediateSpeed[ i ].position[ 2 ] = vSpeed[ i ].position[ 2 ];
	}
}

void DeformableMesh::moveVertex( int vertexId, float dx, float dy, float dz )
{
	m_vertexBuffer[ vertexId ].position[ 0 ] += dx;
	m_vertexBuffer[ vertexId ].position[ 1 ] += dy;
	m_vertexBuffer[ vertexId ].position[ 2 ] += dz;
}

bool DeformableMesh::checkForFractures()
{
	//bool hasFractured = false;

	for( int i = 0; i < numberOfVertices; i++ )
		fractureSpeed[ i ].position[ 0 ] = fractureSpeed[ i ].position[ 1 ] = fractureSpeed[ i ].position[ 2 ] = 0.0f;

	int arcsBroke = 0;

	for (int i = 0; i < numberOfClusters ; i++)
	{
		std::map<int,float>::iterator connection = clusters[ i ]->getConnections().begin();
		while( connection != clusters[ i ]->getConnections().end() )
		{
			int j = connection->first;

			float cXI, cYI, cZI, cXJ, cYJ, cZJ;
			clusters[i]->getCenterOfMass( &cXI, &cYI, &cZI );
			clusters[j]->getCenterOfMass( &cXJ, &cYJ, &cZJ );
			float currDistance = sqrt( pow( cXI - cXJ, 2 ) + pow( cYI - cYJ, 2 ) + pow( cZI - cZJ, 2 ) );
			float stretch = currDistance / clusters[ i ]->getConnectionLength( j );
			if( stretch > 1.5f /* STRECTH COEFFICIENT*/ )
			{
				// the clusters broke
				CONSOLE( "clusters " << i << " and " << j << " broke!" );
				arcsBroke++;
				
				connection++;
				clusters[ i ]->removeConnection( j );
				clusters[ j ]->removeConnection( i );

				std::vector< bool > belongsToICluster = std::vector<bool>();

				for (int vIndex = 0; vIndex < numberOfVertices; vIndex++)
				{
					int vertexClusterIIndex = -1;
					int vertexClusterJIndex = -1;
					for( int clusterIndex = 0; clusterIndex < vertexClusters[ vIndex ].size(); clusterIndex++ )
					{
						int index = vertexClusters[ vIndex ][ clusterIndex ].first;
						if( index == i )
							vertexClusterIIndex = vertexClusters[ vIndex ][ clusterIndex ].second;
						if( index == j )
							vertexClusterJIndex = vertexClusters[ vIndex ][ clusterIndex ].second;
					}


					float iWeight = clusters[ i ]->getVertexWeight( vertexClusterIIndex );
					float jWeight = clusters[ j ]->getVertexWeight( vertexClusterIIndex );
					bool belongsToI = iWeight > jWeight;
					belongsToICluster.push_back( belongsToI );
					
					float absorbedWeight = iWeight + jWeight;
					clusters[ i ]->setVertexWeight( vertexClusterIIndex, belongsToI? absorbedWeight: 0.0f );
					clusters[ j ]->setVertexWeight( vertexClusterJIndex, belongsToI? 0.0f: absorbedWeight );

					float dirIX = ( cXI - cXJ ) / currDistance;
					float dirIY = ( cYI - cYJ ) / currDistance;
					float dirIZ = ( cZI - cZJ ) / currDistance;

					fractureSpeed[ vIndex ].position[ 0 ] += ( belongsToI? dirIX: -dirIX ) * stretch;
					fractureSpeed[ vIndex ].position[ 1 ] += ( belongsToI? dirIY: -dirIY ) * stretch;
					fractureSpeed[ vIndex ].position[ 2 ] += ( belongsToI? dirIZ: -dirIZ ) * stretch;
				}

				//static int HACK = 0;
				//if( HACK < 2 )
				//{
					//if( HACK == 1 )
					//{
						for( int tIndex = 0; tIndex < getNumberOfIndices(); tIndex+=3 )
						{
							int v1 = m_indexBuffer[ tIndex ];
							int v2 = m_indexBuffer[ tIndex + 1 ];
							int v3 = m_indexBuffer[ tIndex + 2 ];

							if( belongsToICluster[ v1 ] != belongsToICluster[ v2 ] ||
								belongsToICluster[ v1 ] != belongsToICluster[ v3 ] ||
								belongsToICluster[ v2 ] != belongsToICluster[ v3 ] )
							{
								// this triangle needs to go!
								m_indexBuffer[ tIndex ] = m_indexBuffer[ tIndex + 1 ] = v3;
							}
						}
					//}
					
					//HACK++;
			//	}
				//else {
				//	int a = 123;
				//}

				// HACK
				//break;
			}
			else
			{
				connection++;
			}
		}
	}

	if( arcsBroke > 0 )
		for(int i = 0; i < numberOfVertices; i++ )
		{
			intermediateSpeed[ i ].position[ 0 ] += fractureSpeed[ i ].position[ 0 ] / ( (float) arcsBroke );
			intermediateSpeed[ i ].position[ 1 ] += fractureSpeed[ i ].position[ 1 ] / ( (float) arcsBroke );
			intermediateSpeed[ i ].position[ 2 ] += fractureSpeed[ i ].position[ 2 ] / ( (float) arcsBroke );
		}

	//std::vector<std::pair<int,int>> toBeRemoved = std::vector<std::pair<int,int>>();
	//std::vector<Arcs> toBeAdded = std::vector<Arcs>();

	//for( int arcId = 0; arcId < arcs.size(); arcId++ )
	//{
	//	int v1Id = arcs[ arcId ].v1Id;

	//	//CONSOLE( "v1Id: " << v1Id );

	//	//for( std::vector<MeshArc>::iterator arc = arcs[ arcId ].arcs.begin(); arc != arcs[ arcId ].arcs.end(); ++arc )
	//	for( int i = 0; i < arcs[ arcId ].arcs.size(); i++ )
	//	{
	//		int v2Id = arcs[ arcId ].arcs[ i ].index;
	//		//CONSOLE( "v2Id: " << v2Id );

	//		ModelOBJ::Vertex v1 = getVertex( v1Id );
	//		ModelOBJ::Vertex v2 = getVertex( v2Id );
	//		float currentDistance = vertexDistance( v1, v2 );

	//		if( currentDistance > arcs[ arcId ].arcs[ i ].length * 2.0f )
	//		{
	//			// we have a tearing!
	//			hasFractured = true;

	//			ModelOBJ::Vertex newVertex;
	//			newVertex.position[ 0 ] = ( v1.position[0] + v2.position[0] ) * 0.5f;
	//			newVertex.position[ 1 ] = ( v1.position[1] + v2.position[1] ) * 0.5f;
	//			newVertex.position[ 2 ] = ( v1.position[2] + v2.position[2] ) * 0.5f;
	//			//newVertex.position[ 0 ] = 0.5f;
	//			//newVertex.position[ 1 ] = 0.5f;
	//			//newVertex.position[ 2 ] = 0.5f;
	//			newVertex.normal[ 0 ] = ( v1.normal[0] + v2.normal[0] ) * 0.5f;
	//			newVertex.normal[ 1 ] = ( v1.normal[1] + v2.normal[1] ) * 0.5f;
	//			newVertex.normal[ 2 ] = ( v1.normal[2] + v2.normal[2] ) * 0.5f;

	//			//CONSOLE( "new vertex position: (" << newVertex.position[ 0 ] << ", " << newVertex.position[ 1 ] << ", " << newVertex.position[ 2 ] << ")" );

	//			int nVertices = m_vertexBuffer.size();
	//			int newIndex = addVertex( -1, &newVertex );

	//			if( nVertices == newIndex )
	//				numberOfVertices++;

	//			if( newIndex < 0 )
	//			{
	//				int a = 123;
	//			}

	//			if( v1Id < v2Id )
	//				toBeRemoved.push_back( std::pair<int,int>(v1Id, v2Id) );
	//			else
	//				toBeRemoved.push_back( std::pair<int,int>(v2Id, v1Id) );

	//			Arcs newV1Arcs;
	//			newV1Arcs.v1Id = v1Id;
	//			MeshArc v1Arcs;
	//			v1Arcs.index = newIndex;
	//			v1Arcs.length = vertexDistance( newVertex, v1 );
	//			newV1Arcs.arcs.push_back( v1Arcs );
	//			toBeAdded.push_back( newV1Arcs );

	//			Arcs newV2Arcs;
	//			newV2Arcs.v1Id = v2Id;
	//			MeshArc v2Arcs;
	//			v2Arcs.index = newIndex;
	//			v2Arcs.length = vertexDistance( newVertex, v2 );
	//			newV2Arcs.arcs.push_back( v2Arcs );
	//			toBeAdded.push_back( newV2Arcs );

	//			vSpeed.push_back( ModelOBJ::Vertex() );				
	//			vSpeed[ newIndex ].position[ 0 ] = 
	//				vSpeed[ newIndex ].position[ 1 ] = 
	//				vSpeed[ newIndex ].position[ 2 ] = 0.0f;

	//			intermediatePosition.push_back( ModelOBJ::Vertex() );
	//			intermediatePosition[ newIndex ].position[ 0 ] = newVertex.position[ 0 ];
	//			intermediatePosition[ newIndex ].position[ 1 ] = newVertex.position[ 1 ];
	//			intermediatePosition[ newIndex ].position[ 2 ] =newVertex.position[ 2 ];

	//			intermediateSpeed.push_back( ModelOBJ::Vertex() );
	//			intermediateSpeed[ newIndex ].position[ 0 ] = 
	//				intermediateSpeed[ newIndex ].position[ 1 ] = 
	//				intermediateSpeed[ newIndex ].position[ 2 ] = 0.0f;

	//			vertexBlockedStatus.push_back( VERTEX_BLOCK_MODE_FREE );

	//			clusters[ 0 ]->addVertex( 
	//				&getVertex( newIndex ), 
	//				&vSpeed[ newIndex ],  
	//				&intermediatePosition[ newIndex ],  
	//				&intermediateSpeed[ newIndex ],
	//				1.0f
	//				);

	//			std::vector<std::pair<int,int>> vClusters = std::vector<std::pair<int,int>>();
	//			vClusters.push_back( std::pair<int,int>( 0, clusters[ 0 ]->getNumberOfVertices() - 1 ) );
	//			vertexClusters.push_back( vClusters );

	//			Color c;
	//			c.color[0] = c.color[1] = c.color[2] = 0.0f;
	//			colorBuffer.push_back( c );

	//			CONSOLE( numberOfVertices << " VS. " << m_vertexBuffer.size() );
	//		}
	//	}
	//}

	//if( hasFractured )
	//{
	//	for( int i = 0; i < toBeRemoved.size(); i++ )
	//	{
	//		Arcs* v1Arcs = NULL;
	//		for( int j = 0; j < arcs.size(); j++ )
	//		{
	//			if( arcs[ j ].v1Id == toBeRemoved[ i ].first )
	//			{
	//				v1Arcs = &arcs[ j ];
	//				break;
	//			}
	//		}

	//		if( v1Arcs )
	//		{
	//			for( std::vector<MeshArc>::iterator it = v1Arcs->arcs.begin(); it != v1Arcs->arcs.end(); ++it )
	//			{
	//				if( it->index == toBeRemoved[i].second )
	//				{
	//					v1Arcs->arcs.erase( it );
	//					break;
	//				}
	//			}
	//		}
	//		else
	//		{
	//			int a = 123;
	//		}
	//	}

	//	for( int i = 0; i < toBeAdded.size(); i++ )
	//	{
	//		Arcs arcsToBeAdded = toBeAdded[ i ];

	//		for( int j = 0; j < arcsToBeAdded.arcs.size(); j++ )
	//		{
	//			bool found = false;
	//			for( int k = 0; k < arcs.size(); k++ )
	//			{
	//				if( arcs[ k ].v1Id == arcsToBeAdded.v1Id )
	//				{
	//					arcs[ k ].arcs.push_back( arcsToBeAdded.arcs[ j ] );
	//					found = true;
	//					break;
	//				}
	//			}
	//			
	//			if( !found )
	//			{
	//				arcs.push_back( arcsToBeAdded );
	//			}
	//		}
	//	}

	//	clusters[ 0 ]->initialize();
	//	CONSOLE( numberOfVertices << " VS. " << m_vertexBuffer.size() );
	//}

	//CONSOLE( "number of vertices: " << numberOfVertices << " VS. " << m_vertexBuffer.size() );
	//if( numberOfVertices != m_vertexBuffer.size() )
	//{
	//	int a = 123;
	//}

	return arcsBroke > 0;
}

//void DeformableMesh::createArcs()
//{
//	for( int i = 0; i < numberOfVertices; i++ )
//	{
//		Arcs newArcs;
//		newArcs.v1Id = i;
//		arcs.push_back( newArcs );c
//	}
//
//	for( int i = 0; i < m_numberOfTriangles; i++ )
//	{
//		int v1 = m_indexBuffer[ i * 3 ];
//		int v2 = m_indexBuffer[ i * 3 + 1 ];
//		int v3 = m_indexBuffer[ i * 3 + 2 ];
//
//		float distFromV1ToV2 = vertexDistance( getVertex( v1 ), getVertex( v2 ) );
//		float distFromV1ToV3 = vertexDistance( getVertex( v1 ), getVertex( v3 ) );
//		float distFromV2ToV3 = vertexDistance( getVertex( v2 ), getVertex( v3 ) );
//
//		if( v1 < v2 )
//		{
//			MeshArc ma;
//			ma.index = v2;
//			ma.length = distFromV1ToV2;
//			arcs[v1].AddArc( ma );
//		}
//		else
//		{
//			MeshArc ma;
//			ma.index = v1;
//			ma.length = distFromV1ToV2;
//			arcs[v2].AddArc( ma );
//		}
//
//		if( v1 < v3 )
//		{
//			MeshArc ma;
//			ma.index = v3;
//			ma.length = distFromV1ToV3;
//			arcs[v1].AddArc( ma );
//		}
//		else
//		{
//			MeshArc ma;
//			ma.index = v1;
//			ma.length = distFromV1ToV3;
//			arcs[v3].AddArc( ma );
//		}
//
//		if( v2 < v3 )
//		{
//			MeshArc ma;
//			ma.index = v3;
//			ma.length = distFromV2ToV3;
//			arcs[v2].AddArc( ma );
//		}
//		else
//		{
//			MeshArc ma;
//			ma.index = v2;
//			ma.length = distFromV2ToV3;
//			arcs[v3].AddArc( ma );
//		}
//	}
//}
